home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 1998 June / SGI Freeware 1998 June.iso / dist / fw_UMINNgopher.idb / usr / freeware / src / gopher_1.12 / gopherd / ftp.c.z / ftp.c
C/C++ Source or Header  |  1997-09-09  |  14KB  |  527 lines

  1. /********************************************************************
  2.  * $Author: drich $
  3.  * $Revision: 1.1 $
  4.  * $Date: 1995/10/03 04:08:28 $
  5.  * $Source: /proj/freeware1.0/gopher1.12/src/gopherd/RCS/ftp.c,v $
  6.  * $Status: $
  7.  *
  8.  * Paul Lindner, University of Minnesota CIS.
  9.  *
  10.  * Copyright 1991, 1992 by the Regents of the University of Minnesota
  11.  * see the file "Copyright" in the distribution for conditions of use.
  12.  *********************************************************************
  13.  * MODULE: ftp.c
  14.  * Routines to translate gopher protocol to ftp protocol.
  15.  *********************************************************************
  16.  * Revision History:
  17.  * $Log: ftp.c,v $
  18.  * Revision 1.1  1995/10/03  04:08:28  drich
  19.  * gopher 1.2 check-in
  20.  *
  21.  * Revision 1.2  1993/01/11  23:18:09  lindner
  22.  * Changed password to be the host of the remote client, not the gateway.
  23.  *
  24.  * Revision 1.1  1992/12/10  23:13:27  lindner
  25.  * gopher 1.1 release
  26.  *
  27.  *
  28.  *********************************************************************/
  29.  
  30.  
  31. /* -------------------------------------------------
  32.  *    g2fd.c          Gopher to FTP gateway daemon.
  33.  *    Version 0.3 Hacked up: April 1992.  Farhad Anklesaria.
  34.  *    Based on a Perl story by John Ladwig.
  35.  *    Based on a Perl story by Farhad Anklesaria.
  36.  *
  37.  *      Modified by Greg Smith, Bucknell University, 24 Nov 1992
  38.  *      to handle multiline status replies.
  39.  *
  40.  ---------------------------------------------------- */
  41.  
  42. #include "gopherd.h"
  43. #include <signal.h>
  44.  
  45. #include <stdio.h>
  46.  
  47.  
  48. #define GFILE    0        /* Gopher item types */
  49. #define GDIR    1
  50. #define GBINHEX    4
  51. #define GDOSB    5
  52. #define GUNIXB    9
  53. #define GIMAGE  "I"
  54. #define GSOUND  "s"
  55.  
  56. #define SLEN    255    /* Generic small buffer length */
  57. #define    TMOUT    180    /* 3 minutes is plenty long enough */
  58.  
  59. int     GLOBALsockfd;   /* For cleanup */
  60. char    *appname;
  61. char    ftptmp[SLEN] = LIST;
  62. char    query[BUFSIZ];                /* input redirected by inetd */
  63. char     *host, *thing;                /* pointers into query */
  64. int    gettingFile = 1;
  65. int    gettingBinary = 0;
  66. int    childpid;
  67.  
  68. /*** Some forward declarations ***/
  69. boolean NotText();
  70. int     Abort();
  71. boolean IsBinaryType();
  72. void    GenerateUniqueFiles();
  73. void    GopherType();
  74. void    Cleanup();
  75. void    RoundEmUp();
  76. void    FailErr();
  77. int     getreply();
  78. /**************************/
  79.  
  80. int
  81. getreply(theStream,inputline,maxlen)
  82.   int theStream;
  83.   char *inputline;
  84.   int maxlen;
  85. {
  86.      int code = 0;
  87.      char origcode[4];
  88.      
  89.  
  90.      readline(theStream, inputline, maxlen);
  91.      if (DEBUG) printf(inputline);
  92.      strncpy(origcode, inputline, 3);  /*** Stash away the original code ***/
  93.  
  94.      while (inputline[3] == '-') {
  95.       if (readline(theStream, inputline, maxlen)<=0)
  96.            return(-1);
  97.       if (DEBUG) printf(inputline);
  98.  
  99.       if (!isdigit(inputline[0]) && !isdigit(inputline[1]) &&
  100.           !isdigit(inputline[2]))
  101.            inputline[3] = '-';
  102.       else
  103.            /*** Keep going if response code isn't the same as original **/
  104.            if (strncmp(origcode, inputline, 3) != 0)
  105.             inputline[3] = '-';
  106.      }
  107.      return (0);
  108. }
  109.  
  110. void
  111. SendFtpQuery(sockfd, query)
  112.   char *query;
  113. {
  114.      int       sLen, termCh;
  115.      char      *at, *cp;
  116.      char      inputline[512];
  117.      char      ipnum[64];
  118.      char      buf[1600];     /*** Nice MTU size ***/
  119.      int       tmpfd;
  120.      int       ftp_control, ftp_data;
  121.      int       ftp_dataport, nRead;
  122.      GopherObj *gs;
  123.  
  124.      /*** hook onto the gs code to do our ftp socket connects ***/
  125.      gs = GSnew();
  126.  
  127.      /** Get ready for some cleanup action **/
  128.      signal(SIGPIPE, Cleanup);
  129.      signal(SIGINT, Cleanup);
  130.      signal(SIGALRM, Cleanup);
  131.  
  132.      if (DEBUG)
  133.       printf("The full query was %s\n", query);
  134.      
  135.      if ((sLen = strlen(query)) <= 2) Abort(sockfd,"No host name specified.");
  136.      host = query;
  137.      at = strchr(query, '@');
  138.      
  139.      if (at == NULL) 
  140.       Abort(sockfd, "Not a valid ftp query.");
  141.      
  142.      GenerateUniqueFiles(ftptmp);
  143.      tmpfd = uopen(ftptmp, O_RDWR|O_CREAT,0755);
  144.      
  145.      if (tmpfd < 0)
  146.       Abort(sockfd, "Sorry, out of tmp transfer space!");
  147.  
  148.      thing = at + 1;
  149.      *at = '\0';             /*Sneakily chop it into two strings*/
  150.  
  151.      sLen = strlen(thing);
  152.      termCh = thing[sLen - 1];            /* Grab possible end char: / etc */
  153.      
  154.      if ((termCh == '*') || (termCh == '@'))  /*  || (termCh == '/')  */
  155.       thing[sLen - 1] = '\0';
  156.      
  157.      if (DEBUG)
  158.       printf("At this point host: %s   thing: %s\n", host, thing);
  159.      
  160.  
  161.  
  162.      /*** Open an ftp control connection ***/
  163.      GSsetHost(gs, host);
  164.      GSsetPort(gs, 21);
  165.      
  166.      ftp_control = GSconnect(gs);
  167.      if (ftp_control < 0)
  168.       Abort(sockfd, "unable to connect to ftp server!");
  169.  
  170.      /*** Strip off the connection message ***/
  171.      getreply(ftp_control,inputline,sizeof inputline);
  172.  
  173.      if (*inputline != '2')
  174.       /*** Some sort of error, urg! ***/
  175.       Abort(sockfd, inputline +3);
  176.  
  177.      /*** Send username ***/
  178.      writestring(ftp_control, "USER anonymous\r\n");
  179.  
  180.      getreply(ftp_control,inputline,sizeof inputline);
  181.  
  182.      if (*inputline != '3')
  183.       /*** Some sort of error, urg! ***/
  184.       Abort(sockfd, inputline +3);
  185.  
  186.      /** Send password***/
  187.      writestring(ftp_control, "PASS -gopher@");
  188.      inet_netnames(sockfd, inputline, ipnum);
  189.      writestring(ftp_control, inputline);
  190.      writestring(ftp_control, "\r\n");
  191.      if (DEBUG) printf("Password was -gopher@%s\n", inputline);
  192.      getreply(ftp_control,inputline,sizeof inputline);
  193.  
  194.      if (*inputline != '2')
  195.       /*** Some sort of error, urg! ***/
  196.       Abort(sockfd, inputline +3);
  197.  
  198.      /**** Send PASV and set up the data port ***/
  199.      writestring(ftp_control, "PASV\r\n");
  200.  
  201.      getreply(ftp_control,inputline,sizeof inputline);
  202.  
  203.      if (strncmp(inputline, "227", 3))
  204.       Abort(sockfd,inputline +3);
  205.      
  206.      /*** Find out the port number of the data connection ***/
  207.      inputline[strlen(inputline)] = '\0';  /** Zap the right paren **/
  208.      cp = strrchr(inputline, ',');         /** lower order octet **/
  209.      if (cp == NULL)  Abort(sockfd,"PASV failed- cannot ftp!");
  210.      *cp = '\0';
  211.      cp ++;
  212.      ftp_dataport = atoi(cp);
  213.  
  214.      cp = strrchr(inputline, ',');         /** upper octet **/
  215.      if (cp == NULL)  Abort(sockfd,"PASV failed- cannot ftp!");
  216.      *cp = '\0';
  217.      cp ++;
  218.      ftp_dataport = atoi(cp) * 256 + ftp_dataport;
  219.      if (DEBUG) printf("Data port is %d\n", ftp_dataport);
  220.  
  221.      GSsetPort(gs, ftp_dataport);
  222.      ftp_data = GSconnect(gs);
  223.      if (ftp_data < 0)
  224.       Abort(sockfd,"Unable to establish data connection!");
  225.  
  226.      
  227.      if (termCh == '/') {    /* We have a directory */
  228.       gettingFile = 0;
  229.  
  230.       writestring(ftp_control, "NLST -LF ");
  231.       if (strlen(thing) > 0)
  232.            writestring(ftp_control, thing);
  233.       writestring(ftp_control, "\r\n");
  234.  
  235.       getreply(ftp_control,inputline,sizeof inputline);
  236.  
  237.       if (*inputline != '1')
  238.            Abort(sockfd,inputline + 4);
  239.      }
  240.      else {                    /* We have a file */
  241.       gettingFile = 1;
  242.       if (gettingBinary = IsBinaryType(thing))  {
  243.            writestring(ftp_control, "TYPE I\r\n");
  244.            getreply(ftp_control,inputline,sizeof inputline);
  245.            if (*inputline != '2')
  246.             Abort(sockfd,"Unable to transfer files in binary");
  247.       }
  248.       writestring(ftp_control, "RETR ");
  249.       writestring(ftp_control, thing);
  250.       writestring(ftp_control, "\r\n");
  251.  
  252.       getreply(ftp_control,inputline,sizeof inputline);
  253.       if (*inputline != '1')
  254.            Abort(sockfd,inputline + 4);
  255.      }
  256.  
  257.      /*** Transfer the data... ***/
  258.      while ((nRead = read(ftp_data, buf, sizeof buf)) > 0)
  259.       writen(tmpfd, buf, nRead);
  260.  
  261.      close(ftp_data);
  262.      
  263.      getreply(ftp_control,inputline,sizeof inputline);
  264.  
  265.      if (*inputline != '2')
  266.       Abort(sockfd,inputline + 3);
  267.  
  268.      writestring(ftp_control, "QUIT\r\n");
  269.  
  270.      getreply(ftp_control,inputline,sizeof inputline);
  271.  
  272.      if (*inputline != '2')
  273.       Abort(sockfd,inputline + 3);
  274.  
  275.      close(ftp_control);
  276. }
  277.  
  278. /*--------------------------------*/
  279. void
  280. TranslateResults(sockfd)
  281.   int sockfd;
  282. {
  283.      FILE  *fp, *OpenOrDie();
  284.      char  buf[BUFSIZ], theName[SLEN];
  285.      int   fd, nRead, checkIt;
  286.      char  outputline[512];
  287.      
  288.      checkIt = 1;
  289.      
  290.      signal(SIGPIPE, Cleanup);
  291.      signal(SIGINT, Cleanup);
  292.  
  293.      if (gettingFile) {
  294.       if (gettingBinary) {                /* icky binary file */
  295.            if (DEBUG)
  296.             printf("Whoa!  That's a binary file\n");
  297.            fp = OpenOrDie(ftptmp, "r");
  298.            fd = fileno(fp);
  299.            
  300.            if (DEBUG)
  301.             printf("fd %d\n",fd);
  302.            while ((nRead = read(fd, buf, sizeof buf)) > 0)
  303.                     writen(sockfd, buf, nRead);
  304.            
  305.            writen(sockfd, buf, nRead);
  306.            fclose(fp);
  307.       } else {            /* must be a nice texty file */
  308.            fp = OpenOrDie(ftptmp, "r");
  309.            while (fgets(buf, sizeof buf, fp) != NULL) {
  310.             if (checkIt) { /* Just peek at it once */
  311.              checkIt = 0;
  312.              if (NotText(buf)) {
  313.                   fclose(fp);
  314.                   Abort(sockfd,"Sorry.  File does not appear to contain text.");
  315.              }
  316.             }
  317.             ZapCRLF(buf);
  318.             FailErr(writestring(sockfd, buf));
  319.             FailErr(writestring(sockfd, "\r\n"));
  320.            }
  321.            fclose(fp);
  322.            FailErr(writestring(sockfd,".\r\n"));
  323.       }
  324.      } else {                       /* Must be a directory */
  325.       fp = OpenOrDie(ftptmp, "r");
  326.       while (fgets(buf, sizeof buf, fp) != NULL) {
  327.            ZapCRLF(buf);
  328.            GopherType(buf, theName);
  329.            sprintf(outputline, "%s\tftp:%s@%s%s\t%s\t%d\r\n", theName,
  330.                host, thing, buf, Zehostname, GopherPort);
  331.            FailErr(writestring(sockfd, outputline));
  332.       }
  333.       fclose(fp);
  334.       FailErr(writestring(sockfd, ".\r\n"));
  335.      }
  336.  
  337.      Cleanup();
  338. }
  339.  
  340. /*--------------------------------*/
  341.  
  342. FILE *OpenOrDie(file, mode)
  343.   char *file, *mode;
  344. {
  345.      FILE *fp, *fopen();
  346.      if ((fp = ufopen(file, mode,0755)) != NULL) {
  347.       return(fp);
  348.      } else {
  349.       Cleanup();
  350.       exit(-1);
  351.      }
  352.      return(NULL);  /** Shouldn't get here **/
  353. }
  354.  
  355.  
  356. /*--------------------------------*/
  357. boolean
  358. NotText(buf)
  359.   char * buf;
  360. {
  361.      int max;   char *c;
  362.      
  363.      if ((max = strlen(buf)) >= (BUFSIZ - 50)) max = BUFSIZ - 50;
  364.      for (c = buf; c < (buf + max); c++) {
  365.       if (*c > '~') return(TRUE);
  366.      }
  367.      return(FALSE);
  368. }
  369.  
  370. /*--------------------------------*/
  371.  
  372. int
  373. Abort(sockfd, complaint)
  374.   int sockfd;
  375.   char *complaint;
  376. {
  377.      char errmsg[512];
  378.      sprintf(errmsg, "3 Error: %s\r\n.\r\n", complaint); 
  379.      writestring(sockfd, errmsg);
  380.      fflush(stdout);
  381.      Cleanup();
  382.      exit(1);
  383. }
  384.  
  385. /*--------------------------------*/
  386.  
  387. boolean
  388. IsBinaryType(thing)
  389.   char *thing;
  390. {
  391.      static char *binExt[] = {
  392.       ".zip", ".zoo", ".arj", ".arc", ".lzh", ".hyp", ".pak", ".exe", ".com",
  393.       ".ps", ".gif", ".pict", ".pct", ".tiff", ".tif", ".tar", ".Z", ".pict", ".au"
  394.       };
  395.      
  396.      int extType, i;
  397.      
  398.      for (extType = 0; extType < 19; extType++) { 
  399.       i = strcasecmp(thing + strlen(thing) - strlen(binExt[extType]),
  400.              binExt[extType]);
  401.       if (i == 0) return(TRUE);
  402.      }
  403.      return(FALSE);
  404.      
  405. }
  406.  
  407. /*--------------------------------*/
  408.  
  409. void
  410. GenerateUniqueFiles(tmpList)
  411.   char *tmpList;
  412. {
  413.      char *s;
  414.      int pid;
  415.      
  416.      pid = getpid();
  417.      s = strchr(tmpList, '+');
  418.      sprintf(s, "%d", pid);
  419. }
  420.  
  421. /*--------------------------------*/
  422.  
  423. void
  424. GopherType(buf, theName)
  425.   char *buf, *theName;
  426. {
  427.      static char ext4[] = ".hqx";
  428.      static char *exts[] = {".au", ".snd"};
  429.      static char *extI[] = {".gif", ".pict", ".tiff", ".tif", ".pcx"};
  430.      static char *ext5[] = {".zip", ".zoo", ".arj", ".arc", ".lzh", ".hyp", 
  431.                  ".pak", ".exe", ".com", ".ps", ".pct"};
  432.      static char *ext9[] = {".tar", ".Z"};
  433.      int extType, i, last;
  434.      char    tmpName[SLEN];    
  435.      
  436.      last = strlen(buf) -1;
  437.  
  438.      strcpy(tmpName, buf);
  439.      if (buf[last] == '/') {
  440.       tmpName[last] = '\0';
  441.       sprintf(theName, "%d%s", GDIR, tmpName);
  442.       return;
  443.      }
  444.      if ((buf[last] == '*') || (buf[last] == '@')) {    /* Hack out * and @ */
  445.       buf[last] = '\0';
  446.       tmpName[last] = '\0';
  447.      }
  448.      
  449.      /* At this point we're looking at a file */
  450.      if (strcasecmp(buf + strlen(buf) - strlen(ext4), ext4) == 0) { /* BinHex? */
  451.       sprintf(theName, "%d%s", GBINHEX, tmpName);
  452.       return;
  453.      }
  454.      
  455.      for (extType = 0; extType < 11; extType++) {  /* PC garbage? */ 
  456.       i = strcasecmp(buf + strlen(buf) - strlen(ext5[extType]), 
  457.              ext5[extType]);
  458.       if (i == 0) {
  459.            sprintf(theName, "%d%s", GDOSB, tmpName);
  460.            return;
  461.       }
  462.      }
  463.      
  464.      for (extType = 0; extType < 2; extType++) {    /* unix binary? */ 
  465.       i = strcasecmp(buf + strlen(buf) - strlen(ext9[extType]), 
  466.              ext9[extType]);
  467.       if (i == 0) {
  468.            sprintf(theName, "%d%s", GUNIXB, tmpName);
  469.            return;
  470.       }
  471.      }
  472.  
  473.      for (extType = 0; extType < 5; extType++) {  /** Image? **/
  474.       i = strcasecmp(buf + strlen(buf) - strlen(extI[extType]), 
  475.              extI[extType]);
  476.       if (i == 0) {
  477.            sprintf(theName, "%s%s", GIMAGE, tmpName);
  478.            return;
  479.       }
  480.      }      
  481.  
  482.      for (extType = 0; extType < 2; extType++) {  /** Image? **/
  483.       i = strcasecmp(buf + strlen(buf) - strlen(exts[extType]), 
  484.              exts[extType]);
  485.       if (i == 0) {
  486.            sprintf(theName, "%s%s", GSOUND, tmpName);
  487.            return;
  488.       }
  489.      }      
  490.      
  491.      sprintf(theName, "%d%s", GFILE, tmpName);
  492.      return;        /* Some other and hopefully text file */
  493. }
  494.  
  495. /*--------------------------------*/
  496.  
  497. void
  498. Cleanup()
  499. {
  500.      unlink(ftptmp);
  501.      if (DEBUG)
  502.       printf("Cleaning up %s\n", ftptmp);
  503.  
  504.      exit(1);
  505. }
  506.  
  507. /*--------------------------------*/
  508. void
  509. RoundEmUp()
  510. {
  511.      
  512.      kill(childpid, SIGKILL);
  513.      Cleanup();
  514. }
  515.  
  516. /*--------------------------------*/
  517. void
  518. FailErr(result)
  519.   int result;
  520. {
  521.      if (result < 0) {
  522.       Cleanup();
  523.      }
  524. }
  525.  
  526. /*--------------------------------*/
  527.